#ifndef CRASH_DUMP_LINUX_H
#define CRASH_DUMP_LINUX_H

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <backtrace.h>  // libbacktrace 核心头文件

namespace CRASHDMP_CPP {
// ------------------------------
// 全局变量声明（静态化，避免多文件包含冲突）
// ------------------------------
// libbacktrace 状态句柄（初始化后复用）
static struct backtrace_state * g_backtrace_state = NULL;
// 崩溃日志文件指针（仅在崩溃时使用）
static FILE* g_crash_log = NULL;
static const char* g_log_prefix = ".";
// ------------------------------
// 前置声明（避免编译警告）
// ------------------------------
static void backtrace_error_cb(void* data, const char* msg, int errnum);
static int backtrace_frame_cb(void* data, uintptr_t pc, const char* filename, int line, const char* function);
void crash_handler(int sig);
void init_crash_handler_once(void);
void init_crash_handler(const char* log_prefix);  // 扩展：自定义日志路径

// ------------------------------
// 扩展接口：自定义崩溃日志保存路径（可选调用）
// 示例：init_crash_handler_with_path("D:/crash_logs");
// ------------------------------
void init_crash_handler(const char* log_prefix) {
    if (log_prefix)
        g_log_prefix = log_prefix;
    init_crash_handler_once();  // 调用核心初始化
}

// ------------------------------
// 1. libbacktrace 错误回调函数（符号解析失败时触发）
// ------------------------------
static void backtrace_error_cb(void* data, const char* msg, int errnum) {
    (void)data;  // 忽略未使用参数，避免编译警告
    // 输出错误信息到日志（日志打开失败则输出到 stderr）
    const char* err_msg = (errnum != 0) ? strerror(errnum) : "NORMAL";
    fprintf(g_crash_log ?: stderr, "BACKTRACE ERROR：%s（CODE：%d，DETAIL：%s）\n", msg, errnum, err_msg);
}

// ------------------------------
// 2. libbacktrace 栈帧回调函数（每个栈帧触发一次）
// ------------------------------
static int backtrace_frame_cb(void* data, uintptr_t pc, const char* filename, int line, const char* function) {
    (void)data;  // 忽略未使用参数
    static int stack_depth = 0;  // 栈深度计数（仅初始化一次）

    // 格式化输出栈帧信息（兼容 C/C++，避免格式警告）
    fprintf(g_crash_log, "[%d] PC: 0x%lx | FUNC: %s | POS: %s:%d\n",
              stack_depth++,
              (unsigned long)pc,
              function ? function : "unknown",  // 空指针安全访问
              filename ? filename : "unknown",
              line > 0 ? line : 0);

    return 0;  // 返回 0 继续回溯下一个栈帧
}

// ------------------------------
// 3. 崩溃信号处理函数（捕获常见崩溃信号）
// ------------------------------
void crash_handler(int sig) {
    // 信号名称映射表（扩展更多常见信号，兼容 MinGW64 环境）
    const char* sig_name = NULL;
    switch (sig) {
    case SIGSEGV: sig_name = "SIGSEGV (段错误/访问非法地址)"; break;
    case SIGABRT: sig_name = "SIGABRT (断言失败/主动终止)";   break;
    case SIGILL:  sig_name = "SIGILL (非法指令)";             break;
    case SIGFPE:  sig_name = "SIGFPE (浮点错误/除零)";        break;
    case SIGBUS:  sig_name = "SIGBUS (总线错误/地址对齐错误)"; break;
    case SIGINT:  sig_name = "SIGINT (用户中断/Ctrl+C)";      break;
    case SIGTERM: sig_name = "SIGTERM (进程终止信号)";        break;
    //case SIGQUIT: sig_name = "SIGQUIT (退出信号/Ctrl+\\)";    break;
    default:      sig_name = "Unknown Signal";                break;
    };

    // 全局变量：日志保存路径（默认当前目录，可通过扩展接口修改）
    time_t now = time(NULL);
    char log_date[16384] = {0};
    char log_filename[16384] = {0};
    strftime(log_date, sizeof(log_date),
             ".crash_log_%Y%m%d_%H%M%S.txt", localtime(&now));
    strcpy(log_filename,g_log_prefix);
    strcat(log_filename,log_date);

    // 打开日志文件（追加模式，若目录不存在则尝试创建）
    g_crash_log = fopen(log_filename, "a");

    // 日志文件仍打开失败，输出到 stderr
    if (!g_crash_log) {
        g_crash_log = stderr;
        fprintf(g_crash_log, "Warning, Log file creation Error ( PATH=%s), stderr is activated instead.\n", log_filename);
    } else {
        // 打印日志文件路径到控制台（方便用户查找）
        fprintf(stdout, "CrashLog created : %s\n", log_filename);
    }

    // 写入崩溃头部信息（兼容 C/C++ 字符串格式）
    fprintf(g_crash_log, "=========================================\n");
    fprintf(g_crash_log, "程序崩溃时间：%s", ctime(&now));
    fprintf(g_crash_log, "崩溃信号：%d（%s）\n", sig, sig_name);
    fprintf(g_crash_log, "堆栈回溯信息（函数名+行号，需编译时加 -g）：\n");

    // 执行栈回溯（skip=1 跳过当前 crash_handler 栈帧）

    /*
extern int backtrace_full (struct backtrace_state *state, int skip,
               backtrace_full_callback callback,
               backtrace_error_callback error_callback,
               void *data);*/
    if (g_backtrace_state != NULL) {
        backtrace_full(g_backtrace_state, 1, backtrace_frame_cb, backtrace_error_cb, (void *)0);
    } else {
        fprintf(g_crash_log, "error：libbacktrace is not inited.\n");
    }

    // 收尾：关闭文件+退出程序（避免无限信号循环）
    fprintf(g_crash_log, "=========================================\n");
    if (g_crash_log != stderr) {
        fclose(g_crash_log);
    }
    g_crash_log = NULL;  // 重置全局指针
    exit(EXIT_FAILURE);

}

// ------------------------------
// 4. 核心初始化接口（必须在程序启动时调用）
// 功能：初始化 libbacktrace + 注册崩溃信号处理器
// ------------------------------
void init_crash_handler_once(void) {
    // 初始化 libbacktrace（线程安全模式，自动获取程序路径）
    g_backtrace_state = backtrace_create_state(NULL, 1, backtrace_error_cb, NULL);

    if (!g_backtrace_state) {
        fprintf(stderr, "Warning：libbacktrace Initial Failed.\n");
        fprintf(stderr, "Possible reason：1. no libbacktrace found. 2. gcc -g not selected. 3. gcc -Wl,-s is enabled in linking time. \n");
        return;
    }

    // 注册常见崩溃信号的处理器（MinGW64 兼容）
    signal(SIGSEGV, crash_handler);  // 段错误
    signal(SIGABRT, crash_handler);  // 断言失败
    signal(SIGILL,  crash_handler);  // 非法指令
    signal(SIGFPE,  crash_handler);  // 浮点错误
    signal(SIGBUS,  crash_handler);  // 总线错误
    signal(SIGINT,  crash_handler);  // 中断信号（可选，根据需求启用）
    signal(SIGTERM, crash_handler);  // 终止信号（可选）

    fprintf(stdout, "CRASGDUMP is online: please enable -g in compile time, and disable -Wl,-s in linking.\n");
}



}



#endif // CRASH_DUMP_LINUX_H
